/**
 * Copyright (c) 2017-2018, zengjintao (1913188966@qq.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jfast.framework.web.core;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;

import com.jfast.framework.aop.Interceptor;
import com.jfast.framework.aop.InterceptorManager;
import com.jfast.framework.orm.dataSource.DataSourceFactory;
import com.jfast.framework.bean.ClassFactory;
import com.jfast.framework.bean.JdkClassFactory;
import com.jfast.framework.job.JfastJobBuild;
import com.jfast.framework.job.JobBuild;
import com.jfast.framework.job.JobManger;
import com.jfast.framework.kit.StrKit;
import com.jfast.framework.log.Logger;
import com.jfast.framework.util.ClassScanner;
import com.jfast.framework.web.annotation.Controller;
import com.jfast.framework.orm.config.DataSourceConfig;
import com.jfast.framework.orm.config.DataSourceConfigManager;
import com.jfast.framework.orm.config.DataSourceManager;
import com.jfast.framework.orm.config.DbConfig;
import com.jfast.framework.web.annotation.RequestMapping;
import com.jfast.framework.web.handler.ContextPathHandler;
import com.jfast.framework.web.handler.Handler;
import com.jfast.framework.web.handler.HandlerManager;
import com.jfast.framework.web.handler.JfastHandler;
import com.jfast.framework.web.plugin.IPlugin;
import com.jfast.framework.web.plugin.PluginManager;
import org.eclipse.jetty.io.RuntimeIOException;

public class Config {
	
	private static final Logger logger = Logger.getLogger(Config.class);
	private static final List<Class<?>> controllerClass = new ArrayList<>();
	private static final Config config = new Config();
	private final ClassFactory classFactory = new JdkClassFactory();
	private static final PluginManager pluginManager = PluginManager.getPluginManger();
	private static final InterceptorManager interceptorManager = InterceptorManager.getInteceptorManager();
	private static final HandlerManager handlerManager = HandlerManager.getHandlerManager();
	private static final RequestMethodMappingManager requestMethodMappingManager = RequestMethodMappingManager.getRequestMethodMappingManager();
	public static Config getConfig(){
		return config;
	}
	
	/**
	 * 初始化系统配置
	 */
	public void init(){
		initRequestMapping();
		initPlugins();
		initInterceptor();
		initHandler();
		initDataSource();
		startJob();
	}

	/**
	 * 启动系统job
	 */
	private void startJob() {
		List<Class<?>> jobList = ClassScanner.getClassByAnnoation(JobBuild.class);
		JobManger jobManger = JobManger.getJobManger();
		for (Class<?> clazz : jobList) {
			JfastJobBuild jfastBuild = (JfastJobBuild) classFactory.createSingletonBean(clazz);
			jobManger.addJfastBuild(jfastBuild);
		}
		jobManger.start();
	}

	private void initHandler() {
		handlerManager.add(new ContextPathHandler());
		handlerManager.add(new JfastHandler());
		List<Class<?>> clazzes = ClassScanner.getSubClassByParent(Handler.class);
		for (Class<?> clazz : clazzes) {
			try {
				Handler handler = (Handler) classFactory.createSingletonBean(clazz);
				handlerManager.add(handler);
			} catch (Exception e) {
				throw new RuntimeIOException("can not cast the class to Handler", e);
			}
		}
	}

	private void initDataSource() {
		List<DataSourceConfig> dataSourceConfigs = DataSourceConfigManager.getDataSourceConfigManager().getDataSourceConfigs();
		//加载数据源配置
		for (DataSourceConfig dataSourceConfig : dataSourceConfigs) {
			DataSourceFactory dataSourceFactory = DataSourceManager.createDataSourceFactory(dataSourceConfig);
			DataSourceManager.addDbConfig(new DbConfig(dataSourceFactory));
		}
	}
	
	
	/**
	 * 初始化拦截器
	 */
	private void initInterceptor() {
		List<Class<?>> clazzes = ClassScanner.getSubClassByParent(Interceptor.class);
		for (Class<?> clazz : clazzes) {
			try {
				Interceptor interceptor = (Interceptor) classFactory.createSingletonBean(clazz);
				interceptorManager.add(interceptor);
			} catch (Exception e) {
				throw new RuntimeIOException("can not cast the class to IPlugin", e);
			}
		}
	}


	/**
	 * 初始化插件配置
	 */
	private void initPlugins() {
		List<Class<?>> clazzes = ClassScanner.getSubClassByParent(IPlugin.class);
		for (Class<?> clazz : clazzes) {
			try {
				IPlugin iPlugin = (IPlugin) classFactory.createSingletonBean(clazz);
				pluginManager.add(iPlugin);
			} catch (Exception e) {
				throw new RuntimeIOException("can not cast the class to IPlugin", e);
			}
		}
		List<IPlugin> plugins = pluginManager.getPlugins();
		for (IPlugin plugin : plugins) {
			try {
				if (!plugin.start()) {
					String message = "Plugin start error: " + plugin.getClass().getName();
					logger.error(message);
					throw new RuntimeException(message);
				}
			} catch (Exception e) {
				String message = "Plugin start error: " + plugin.getClass().getName() + ". \n" + e.getMessage();
				logger.error(message, e);
				throw new RuntimeException(message, e);
			}
		}
	}

	/**
	 * 初始化路由映射
	 */
	@SuppressWarnings({ "rawtypes","unchecked" })
	private void initRequestMapping() {
		List<Class<?>> classes = getControllerClass();
		RequestMapping requestMapping = null;
		for (Class cla : classes) {
		    requestMapping = (RequestMapping) cla.getAnnotation(RequestMapping.class);
			String controllerKey = requestMapping == null ? "" : requestMapping.value();
			Method[] methods = cla.getDeclaredMethods();
			String methodMapping = null;
			for (Method method : methods) {
				requestMapping = method.getAnnotation(com.jfast.framework.web.annotation.RequestMapping.class);
				if (requestMapping == null) {
					methodMapping = JfastConstant.SEPARATOR + StrKit.toLowerCaseFirst(method.getName());
				} else {
					methodMapping = requestMapping.value();
					if (!methodMapping.startsWith("/")) {
						methodMapping = "/" + methodMapping;
					}
				}
				
				if (StrKit.isNotEmpty(controllerKey) && !methodMapping.equals("/")) {
					methodMapping = controllerKey + methodMapping;
				}

				List<String> pathVariableParams = null;
				Pattern urlPattern = null;

				//判断url 是否含有占位符
				if (methodMapping.matches(".+\\{\\w+\\}.*")) {
                    pathVariableParams = StrKit.parsePlaceholder("{", "}", methodMapping); //解析占位符
                    String regex = StrKit.replaceAll(methodMapping, "\\{\\w+\\}", "(\\\\w+)");
                    urlPattern = Pattern.compile(regex);
				}
				RequestMethod[] requestType = requestMapping == null ? null : requestMapping.method();
				RequestMethodMapping requestMethodMapping = new RequestMethodMapping(controllerKey, methodMapping, method,
						cla, pathVariableParams, requestType);
				if (urlPattern != null) {
					requestMethodMappingManager.putPatternMapping(urlPattern, requestMethodMapping);
				} else {
					requestMethodMappingManager.putMapping(methodMapping, requestMethodMapping);
				}
				logger.info("requestMapping: " + methodMapping + "  method: " + requestMethodMapping.getMethod());
			}
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private List<Class<?>> getControllerClass() {
		List<Class<?>> classes = ClassScanner.getClassByAnnoation(Controller.class);
		for (Class cla : classes) {
			Controller controller = (Controller) cla.getAnnotation(Controller.class);
			if (controller != null) {
				controllerClass.add(cla);
			}
		}
		return controllerClass;
	}
}
